package org.sucri.servlet;

/** Adapted from an example below.
 *  http://extjs.com/forum/archive/index.php/t-7239.html
 * 
 * User: Wen Yu
 * Date: Jul 26, 2007
 * Time: 11:32:43 PM
 * To change this template use File | Settings | File Templates.
 */

import java.io.*;
import java.util.Date;
import java.util.Hashtable;
import java.util.zip.GZIPOutputStream;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class serveScript extends HttpServlet {
  private static final long serialVersionUID = 1L;
  private static Hashtable<String, byte[]> jsCache = new Hashtable<String, byte[]>();

  public void doPost(HttpServletRequest req, HttpServletResponse resp)
      throws ServletException {
    doGet(req, resp);
  }

  public void doGet(HttpServletRequest request, HttpServletResponse response)
      throws ServletException
  {
    boolean zipped = true;
    String fileName = request.getRequestURI();
    int s = fileName.indexOf('/', 1);
    if (s != -1)
      fileName = fileName.substring(s + 1);

    fileName = this.getServletContext().getRealPath((fileName.indexOf("extjs") == 0) ? "js/" + fileName : fileName);            

    File jsFile = new File(fileName);
    if (!jsFile.exists()) {
      response.setStatus(HttpServletResponse.SC_NOT_FOUND);
      return;
    }
    long modifiedValue = jsFile.lastModified();
    Date modified = new Date(modifiedValue);
    long contentLength = jsFile.length();
    String etag = "W/\"" + contentLength + "-" + Long.toString(modifiedValue) + "\"";
    response.setHeader("Etag", etag);

    String ifNoneMatch = request.getHeader("If-None-Match");
    if (ifNoneMatch != null) {
      if (ifNoneMatch.equals(etag)) {
// Return visit and no modifications, so do not send anything
        response.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
        return;
      }
// The user agent requested an outdated version - ensure it's not cached
      jsCache.remove(ifNoneMatch);
    }

// Extract the last cached date from the request.
// If present, this will be in RFC822 format eg: "Fri, 08 Dec 2006 09:30:32 GMT"
    Date lastAccessDate = null;
    String lastAccessDateStr = request.getHeader("If-Modified-Since");
    if (lastAccessDateStr != null)
      lastAccessDate = new Date(lastAccessDateStr);

    try {
// If the If-Modified-Since header was sent, see if we can save bandwidth.
      if (lastAccessDate != null) {
        if (!modified.after(lastAccessDate)) {
          response.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
          return;
        }
      }

// It *has* been modified since they last got it, so send it.
      if (fileName.indexOf(".css") > 0)
      {
        response.setContentType("text/css");
      }
      else if (fileName.indexOf(".js") > 0)
      {
        response.setContentType("text/javascript");
      }
      else if (fileName.indexOf(".jpg") > 0)
      {
        response.setContentType("image/jpeg");
        zipped = false;
      }
      else if (fileName.indexOf(".gif") > 0)
      {
        response.setContentType("image/gif");
        zipped = false;
      }
      else
      {
        zipped = false;
      }
      response.setHeader("Last-Modified", modified.toString());

      // Attempt to get content fron cache
      byte[] content = jsCache.get(etag);
      if (content != null) {
        response.setHeader("Content-Length", Integer.toString(content.length));
        response.getOutputStream().write(content);
        return;
      }

      // Copy the bytes from the soure file into the GZIPOutputStream which
      // is wrapping a ByteArrayOutputStream
      ByteArrayOutputStream b = new ByteArrayOutputStream((int) (contentLength / 3));
      OutputStream out = null;
      if (zipped)
      {
        response.setHeader("Content-Encoding", "gzip");
        out = new GZIPOutputStream(b);
      }
      else
      {
        out = new BufferedOutputStream(b);
      }
      InputStream in = new FileInputStream(jsFile);
      byte[] buffer = new byte[16384];
      int bufferFill = in.read(buffer);
      while (bufferFill != -1)
      {
        out.write(buffer, 0, bufferFill);
        bufferFill = in.read(buffer);
      }
      out.close();
      in.close();

      // Write the compressed bytes to the output, and cache them.
      content = b.toByteArray();

      response.setHeader("Content-Length", Integer.toString(content.length));
      response.getOutputStream().write(content);
      jsCache.put(etag, content);
    }
    catch (Exception e) {
//Logger.error(e);
      throw new ServletException(e.getMessage(), e);
    }
  }
}